Skip to content

fix(quick-router): match lock and door tokens as whole words in home_status - #832

Merged
matedev01 merged 3 commits into
GeniePod:mainfrom
michiot05:fix/lock-status-whole-word
Jul 24, 2026
Merged

fix(quick-router): match lock and door tokens as whole words in home_status#832
matedev01 merged 3 commits into
GeniePod:mainfrom
michiot05:fix/lock-status-whole-word

Conversation

@michiot05

@michiot05 michiot05 commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

home_status_target matched its lock/door device group with a bare contains, so a word that merely contains "lock"/"door" as a substring misrouted to home_status"is the clock on" (c[lock]) reported the door locks, and "out[door]" collided the same way. Match the tokens as whole words, mirroring the existing ice/iron/cooktop/cover fixes. Closes #831.

Changes

  • In home_status_target, replace the substring contains_any(&target, &["lock", "locks", "door lock", "door locks", "door"]) with a whole-word target.split_whitespace().any(|word| matches!(word, "lock" | "locks" | "door" | "doors")). The multi-word "door lock"/"door locks" entries are redundant once the words match and are dropped; "doors" is added so "are the doors locked" keeps resolving.
  • New test lock_and_door_status_match_whole_words_not_substrings: three substring cases (clock/block) must not resolve to "locks"; four genuine lock/door queries (bare → "locks", named → full entity) must still resolve.

Real Behavior Proof

  • I have built and run the affected code locally (or noted why I could not).
  • I have verified the change end-to-end on Jetson hardware.
  • I have NOT verified on Jetson hardware, and I explain the equivalent verification path or validation gap below.

Tested profile / hardware (check all that apply):

  • jetson
  • raspberry_pi
  • portable_sbc
  • laptop
  • mac
  • CI-only / docs-only
  • Not run locally

What I ran

x86_64 Linux dev machine (laptop profile), rustc 1.98.0-nightly, branch cut from 7c67906. The changed path is pure string routing in quick::route — no audio/HA/hardware dependency — so route() unit tests exercise it end-to-end; the validation gap is only that I did not run the voice loop on a device.

  1. Wrote the failing test first and ran it against unmodified main: cargo test -p genie-core --lib lock_and_door_status
  2. Applied the fix and re-ran, then the full gates:
    • cargo fmt --all -- --check
    • cargo clippy -p genie-core --all-targets --locked -- -D warnings
    • cargo test -p genie-core --lib and cargo test -p genie-core --lib --no-default-features

What I observed

Before the fix (new test against unmodified main):

"is the clock on" must not resolve to the locks status entity
test result: FAILED. 0 passed; 1 failed

i.e. route("is the clock on")home_status{entity:"locks"}.

After the fix:

  • route("is the clock on") → abstains
  • route("is the wall clock right") → abstains
  • route("is the block heater on") → abstains
  • unchanged: "are the doors locked" / "is the door locked"home_status{entity:"locks"}; "is the side door locked""side door"; "is the garage door closed""garage door"

Gate results: fmt clean; clippy clean under -D warnings; lib tests 938 passed / 0 failed (default) and 840 passed / 0 failed (--no-default-features). The existing door/lock status tests ("Is the garage door closed?""garage door", "Is the side door locked?""side door", "What doors are unlocked?""unlocked doors") continue to pass.

Test plan

  • cargo test -p genie-core --lib lock_and_door_status — the new case fails on main, passes here.
  • cargo test -p genie-core --lib status — the home_status suite (including the existing whole-word sibling tests) stays green.

Notes for reviewers

This is the same substring→whole-word conversion applied to the neighbouring groups in #792 (ice/iron/cooktop) and #802 (cover/gate); the lock/door group was the remaining substring matcher in home_status_target. "outdoor" no longer trips the door arm, and "clock"/"block" no longer trip the lock arm, while "doors" was added to the token set so the bare-plural "are the doors locked" still collapses to "locks".

Summary by CodeRabbit

  • Bug Fixes
    • Improved lock and door query detection by matching whole words instead of substring text, preventing false matches from unrelated phrases containing “door” or “lock” as part of other words.
    • Added test coverage to verify abstention for common false-positive examples while preserving correct routing for genuine queries like “doors locked,” “side door locked,” and “garage door closed.”

…status

home_status_target matched the lock/door group with a bare contains, so a
common word that merely contains the token misrouted to home_status
"locks" instead of abstaining: "is the clock on" (c[lock]) reported the
door locks, and "out[door]" collided the same way. Mirrors the existing
ice/iron/cooktop/cover whole-word fixes: match lock/locks/door/doors via
split_whitespace().any(...). The multi-word "door lock"/"door locks"
entries are redundant once the words match, and are dropped.
@github-actions github-actions Bot added the bug Something isn't working label Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5548282d-02e9-4ac2-b128-ad32d550ccb4

📥 Commits

Reviewing files that changed from the base of the PR and between af8589d and 19cc6b6.

📒 Files selected for processing (1)
  • crates/genie-core/src/tools/quick.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/genie-core/src/tools/quick.rs

📝 Walkthrough

Walkthrough

home_status_target now detects lock and door terms as whole words instead of substrings. Regression tests cover unrelated phrases and valid lock and door queries.

Changes

Lock and door status routing

Layer / File(s) Summary
Whole-word matching and regression coverage
crates/genie-core/src/tools/quick.rs
home_status_target uses whitespace-delimited exact token checks for lock and door terms, with tests covering false positives and valid status targets.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: whole-word lock/door matching in home_status.
Linked Issues check ✅ Passed The PR implements #831 by switching to whole-word token matching, abstaining on substring collisions, and preserving valid lock/door routes.
Out of Scope Changes check ✅ Passed The changes stay focused on quick-router matching logic and regression tests, with no unrelated scope added.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/genie-core/src/tools/quick.rs`:
- Around line 5565-5575: Update the route assertions in the relevant test to
require route(utterance).is_none(), ensuring each unrelated query abstains
entirely rather than routing to another entity; also add an explicit “outdoor”
utterance case to the test inputs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f1a4e7df-fa5b-4c92-991d-376f26ce9ebf

📥 Commits

Reviewing files that changed from the base of the PR and between 7c67906 and eef3047.

📒 Files selected for processing (1)
  • crates/genie-core/src/tools/quick.rs

Comment thread crates/genie-core/src/tools/quick.rs
Strengthen the substring-collision assertions from "entity is not locks"
to route().is_none(), so the test fails if any of these ever route
through home_status with a different (garbled) entity. Add the
"are the outdoor cameras on" case, which the substring door match
misrouted to home_status "outdoor cameras".
@michiot05

Copy link
Copy Markdown
Contributor Author

Good call — applied in af8589d. The substring cases now assert route(utterance).is_none() (full abstention, so the test fails if any of them ever routes through home_status with a different garbled entity), and I added the are the outdoor cameras on case you suggested — that one misrouted to home_status{entity:"outdoor cameras"} on the substring path (out[door]), so it's a good regression to pin.

All four now abstain; cargo fmt / clippy -D warnings / cargo test -p genie-core --lib (+ --no-default-features) green.

@matedev01 matedev01 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — lock/door tokens in home_status_target now match as whole words, so 'is the clock on' (c[lock]) no longer misroutes to door locks. Same substring-safety class as the prior whole-word fixes. Verified: clippy -D warnings clean, quick-router tests (99) pass, fmt clean, live BFCL strict_accuracy 96.15% (no regression).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] quick-router: "is the clock on" misroutes to home_status "locks" — lock/door tokens matched as substrings

2 participants